import React, {PureComponent} from "react"
import PropTypes from "prop-types"
import HTML5Backend from "react-dnd-html5-backend"
import { DragDropContext, DropTarget } from "react-dnd"
import Item from "./Item"
import ItemTypes from "./itemType"
import "./styles.less"
import update from "immutability-helper"
import cs from "classnames"


const defaultItemRender = (uniqueKey) => (data,index)=>{
  return (<span>{ `${index}:${ data ? data[uniqueKey] : "" }` }</span>)
}


@DragDropContext(HTML5Backend)
@DropTarget(ItemTypes.ITEM, {}, connect => ({
  connectDropTarget: connect.dropTarget(),
}))
class DragList extends PureComponent {

  constructor(props) {
    super(props)
    this.state = {
      list: props.list || [],
      uniqueKey: props.uniqueKey || "id",
      selected: props.selectItem || {},
      itemRender:props.itemRender || defaultItemRender(props.uniqueKey || "id")
    }
  }

  onHover = (source, target) => {
    const {uniqueKey} = this.state
    if (source[uniqueKey]===target[uniqueKey]) {
      return
    }
    const listKeys = this.state.list.map(i => i[uniqueKey])
    const sourceIndex = listKeys.indexOf(source[uniqueKey])
    const targetIndex = listKeys.indexOf(target[uniqueKey])

    this.setState({
      list: update(this.state.list, { $splice: [[sourceIndex, 1], [targetIndex, 0, source]] })
    })
  }

  onEndDrag = () => {
    if (this.props.onChange) this.props.onChange(this.state.list)
  }

  onItemClick = (data) => {
    this.setState({
      selected: data
    })
    if (this.props.onSelect) this.props.onSelect(data)
  }

  csItem = (item) => {
    return cs({
      "selected": this.state.selected[this.state.uniqueKey] === item[this.state.uniqueKey]
    })
  }

  render() {

    const { connectDropTarget } = this.props
    const {list, uniqueKey} = this.state

    return connectDropTarget(
      <ul className="drag-container">
        { list.map((item, index) =>
          <Item
            className={ this.csItem(item) }
            uniqueKey={uniqueKey}
            data={item}
            key={ `drag-item-${item[uniqueKey]}` }
            onHover = { this.onHover }
            onEndDrag = { this.onEndDrag }
            onItemClick = { this.onItemClick }
          >
            { this.state.itemRender(item, index) }
          </Item>)
        }
      </ul>
    )
  }

  componentWillReceiveProps(nextProps) {
    const nextState = {
      list: nextProps.list || [],
    }
    if(nextProps.selectItem){
      nextState.selected = nextProps.selectItem
    }
    this.setState(nextState)
  }

}


DragList.propTypes = {

  /**
   * 列表项根据数据渲染，返回一个React组件或string
   * @param data 列表中单个数据项
   * */
  itemRender: PropTypes.func,

  /**
   * 列表数据，列表数据项中必须包含一个唯一标识属性，默认为id
   * */
  list: PropTypes.array,

  /**
   * 标识数据列表项属性唯一标识名称，默认id
   * */
  uniqueKey: PropTypes.string,

  /**
   * 数据排序变更时
   * @param list 当前排序下的列表
   * */
  onChange: PropTypes.func,

  /**
   * 当列表项被选中时
   * @param data 当前被选中列表对应的数据
   * 定义被选中列表样式，选择器：.drag-list-item.selected
   * */
  onSelect: PropTypes.func,

  /**
   * 设置被选中数据项
   * */
  selectItem:PropTypes.object

}

export default DragList